from fastapi import FastAPI, Request, HTTPException
from fastapi.responses import JSONResponse
from tortoise import Tortoise
from tortoise.contrib.fastapi import register_tortoise
from config import settings
from controller.register import register_routes
from fastapi.exceptions import RequestValidationError
from tortoise.exceptions import DoesNotExist, OperationalError
from utils.response import ResponseUtil
import logging
import traceback
from starlette.responses import Response, StreamingResponse
from starlette.middleware.base import BaseHTTPMiddleware
from fastapi.responses import JSONResponse
from starlette.types import Message
from typing import Union
from utils.auth import AuthMiddleware

from apscheduler.schedulers.asyncio import AsyncIOScheduler
from model.sysJobModel import SysJob
from service.sysJobService import SysJobService

# 配置日志
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

# 创建调度器实例
scheduler = AsyncIOScheduler()


class ResponseMiddleware(BaseHTTPMiddleware):
    async def dispatch(self, request: Request, call_next):
        try:
            response = await call_next(request)

            # 检查是否为文件下载响应
            if isinstance(response, StreamingResponse):
                return response

            # 处理 404 错误
            if response.status_code == 404:
                return JSONResponse(
                    status_code=200,
                    content={
                        "code": 404,
                        "msg": "资源不存在",
                        "data": None
                    }
                )

            # 如果是 JSONResponse，检查内容是否已经是预期的格式
            if isinstance(response, JSONResponse):
                content = response.body.decode()
                if '"img":' in content:  # 如果响应中包含 img 字段，说明是验证码响应，直接返回
                    return response

            return response
        except Exception as e:
            logger.error(f"Middleware error: {str(e)}\n{traceback.format_exc()}")
            return JSONResponse(
                status_code=200,
                content={
                    "code": 500,
                    "msg": "服务器内部错误",
                    "data": None
                }
            )


def create_application() -> FastAPI:
    application = FastAPI(
        title=settings.APP_NAME,
        debug=settings.DEBUG,
        openapi_url=f"{settings.API_STR}/openapi.json"
    )

    # 添加中间件 - 注意顺序，认证中间件应该在响应中间件之前
    # 认证中间件
    application.add_middleware(AuthMiddleware)
    # 加响应中间件
    application.add_middleware(ResponseMiddleware)

    async def init_scheduler():
        """Initialize the scheduler and load jobs"""
        try:
            logger.info("Initializing scheduler...")

            # 启动调度器
            scheduler.start()

            # 从数据库加载所有启用的任务
            jobs = await SysJob.filter(status='0', job_status='0').all()

            for job in jobs:
                try:
                    # 为每个任务启动调度
                    result = await SysJobService.start_scheduled_job(job.job_id, scheduler)
                    logger.info(f"Scheduled job {job.job_name} (ID: {job.job_id}): {result}")
                except Exception as e:
                    logger.error(f"Failed to schedule job {job.job_name} (ID: {job.job_id}): {str(e)}")

            logger.info("Scheduler initialized successfully")

        except Exception as e:
            logger.error(f"Failed to initialize scheduler: {str(e)}")

    # 在应用启动时初始化
    @application.on_event("startup")
    async def startup_event():
        # 首先初始化数据库连接
        await Tortoise.init(config=settings.TORTOISE_ORM)

        # 然后初始化调度器
        await init_scheduler()

    # 在应用关闭时清理
    @application.on_event("shutdown")
    async def shutdown_event():
        try:
            logger.info("Shutting down scheduler...")
            scheduler.shutdown()
            logger.info("Scheduler shut down successfully")
        except Exception as e:
            logger.error(f"Error shutting down scheduler: {str(e)}")

        # 关闭数据库连接
        await Tortoise.close_connections()

    # 添加调度器到应用的状态中
    application.state.scheduler = scheduler

    # 处理 Tortoise ORM 的 OperationalError
    @application.exception_handler(OperationalError)
    async def database_exception_handler(request: Request, exc: OperationalError):
        logger.error(f"Database error: {str(exc)}\n{traceback.format_exc()}")
        return JSONResponse(
            status_code=200,
            content={
                "code": 400,
                "msg": "数据库操作错误:" + str(exc),
                "data": None
            }
        )

    # 处理请求参数验证错误
    @application.exception_handler(RequestValidationError)
    async def validation_exception_handler(request: Request, exc: RequestValidationError):
        logger.error(f"Validation error: {str(exc.errors())}")
        return JSONResponse(
            status_code=200,
            content={
                "code": 422,
                "msg": "请求参数验证失败:" + str(exc),
                "data": None
            }
        )

    # 处理 FastAPI 的 HTTPException（包括 404）
    @application.exception_handler(HTTPException)
    async def http_exception_handler(request: Request, exc: HTTPException):
        logger.info(f"HTTP exception occurred: {exc.status_code} - {exc.detail}")
        return JSONResponse(
            status_code=200,
            content={
                "code": exc.status_code,
                "msg": str(exc.detail),
                "data": None
            }
        )

    # 处理其他所有异常
    @application.exception_handler(Exception)
    async def global_exception_handler(request: Request, exc: Exception):
        logger.error(f"Unhandled exception: {str(exc)}\n{traceback.format_exc()}")
        return JSONResponse(
            status_code=200,
            content={
                "code": 500,
                "msg": "服务器内部错误:" + str(exc) if settings.DEBUG else "Internal Server Error",
                "data": None
            }
        )

    # 注册所有路由
    register_routes(application, api_prefix=settings.API_STR)

    # 注册Tortoise ORM
    register_tortoise(
        application,
        config=settings.TORTOISE_ORM,
        generate_schemas=False,
        add_exception_handlers=True,
    )

    return application


app = create_application()

if __name__ == "__main__":
    import uvicorn

    uvicorn.run(app, host="0.0.0.0", port=8080)
